package cn.dianchiyun.protocol.netty.dtu.handler;

import cn.dianchiyun.protocol.netty.dtu.entity.DTURead;
import cn.dianchiyun.protocol.netty.utils.ByteUtil;
import cn.dianchiyun.protocol.netty.utils.HexUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.List;

public class MyDecoderHandler1 extends ByteToMessageDecoder {
    private static final Logger logger = LogManager.getLogger("dtu_server");
    //设备注册码的长度
    private final int BASE_LENGTH = 2;

    //设备注册码的长度
    private final int SERIAL_CODE_LENGTH = 12;

    private final byte HEAD_DATA = 0x24;

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> out) throws Exception {
        try {
            //基础长度不足，我们设定基础长度为4
            if (in.readableBytes() < SERIAL_CODE_LENGTH) {
                return;
            }
            int beginIdx; //记录包头位置
            while (true) {
                // 防止socket字节流攻击
                // 防止，客户端传来的数据过大
                // 因为，太大的数据，是不合理的
                if (in.readableBytes() > 2048) {
                    in.skipBytes(in.readableBytes());
                }
                // 获取包头开始的index
                beginIdx = in.readerIndex();
                // 标记包头开始的index
                in.markReaderIndex();
                // 读到了协议的开始标志，结束while循环
                byte hd = in.readByte();
                System.out.print(HexUtil.byte2Str(hd)+" ");
                if (hd == HEAD_DATA) {
                    break;
                }
                // 未读到包头，略过一个字节
                // 每次略过，一个字节，去读取，包头信息的开始标记
                in.resetReaderIndex();
                in.readByte();
                // 当略过，一个字节之后，
                // 数据包的长度，又变得不满足
                // 此时，应该结束。等待后面的数据到达
                if (in.readableBytes() < BASE_LENGTH) {
                    return;
                }
            }

            //剩余长度不足可读取数量不够设备注册码的长度
            int readableCount0 = in.readableBytes();
            if (readableCount0 < SERIAL_CODE_LENGTH) {
                in.readerIndex(beginIdx);
                return;
            }

            //设备注册码处理
            byte[] bytes = new byte[SERIAL_CODE_LENGTH];
            in.readBytes(bytes);
            String serialCode = HexUtil.byte162Str(bytes);

            /*System.out.println(bytes.length);

            for(int a=0; a<bytes.length; a++){
                System.out.println(String.valueOf((char)bytes[a]));
            }*/

            //如果是已读完了，那么说明这个包是心跳包,并且后面没有粘包
            int readableCount1 = in.readableBytes();

            if (readableCount1 == 0) {
                DTURead dtuRead = new DTURead(serialCode, true);
                out.add(dtuRead);
            } else {
                //如果还没有读完，但是下一个字节就是数据的开始字节的话，那么也是心跳包
                byte headData = in.readByte();
                System.out.println("in.readableBytes()" + in.readableBytes());
                if (headData == HEAD_DATA) {
                    DTURead dtuRead = new DTURead(serialCode+"a", true);
                    out.add(dtuRead);
                } else {
                    int readableCount3 = in.readableBytes();
                    if (readableCount3 < 12) {
                        in.readerIndex(beginIdx);
                        return;
                    }
                    buildDTURead(in, out, beginIdx, readableCount3,serialCode+"b", headData);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 构建消息
     * @param in
     * @param out
     * @param beginIdx
     * @param readableCount
     * @param serialCode
     * @param headData
     */
    private void buildDTURead(ByteBuf in, List<Object> out, int beginIdx, int readableCount, String serialCode, byte headData) {
        String address = HexUtil.byte2Str(headData);
        String funCode = HexUtil.byte2Str(in.readByte());
        int dataLength = (int)in.readByte();

        if(readableCount < dataLength + 4 ) {
            in.readerIndex(beginIdx);
            return;
        }

        byte[] dataBytes = new byte[dataLength];
        in.readBytes(dataBytes);

        Integer[] datas = new Integer[dataLength/2];

        int indexNow = 0;
        for (int i = 0; i < dataLength / 2; i++) {
            datas[i] = ByteUtil.getInt(new byte[]{dataBytes[indexNow + 1], dataBytes[indexNow]}, true);
            indexNow += 2;
            System.out.print(datas[i] + "\t");
        }
        System.out.println("\t");

        //处理CRC16
        byte crc0 = in.readByte();
        byte crc1 = in.readByte();
        int crc16 = ByteUtil.getInt(new byte[]{crc1, crc0}, true);
        logger.error("CRC:"+crc16);

        DTURead dtuRead = new DTURead(serialCode, false, address, funCode, dataLength, dataBytes, datas, crc16);
        out.add(dtuRead);
    }

}